package com.duoduo.common.api.help;

import com.duoduo.common.api.JsonDeserializationException;
import com.duoduo.common.api.constants.Constant;
import com.duoduo.common.api.constants.LogConstant;
import com.duoduo.common.api.domain.JsonContainerClass;
import com.duoduo.common.api.myinterface.JsonOperator;
import com.duoduo.common.api.spi.extension.ExtensionLoader;
import com.duoduo.common.api.tuple.TwoTuple;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Objects;

public class JsonInnerUtil {
	
	private static Logger logger = LoggerFactory.getLogger(JsonInnerUtil.class);
	private static String jsonType;
	private static JsonOperator jsonOperator;
	static {
		try{
			jsonType = SpringContextInnerUtil.get(Constant.JSON_TYPE);
			if(jsonType == null){
				jsonType = Constant.JSON_TYPE_DEFAULT;
				logger.error(LogConstant.JSON + " init error: no jsonType");
			}
			jsonOperator = ExtensionLoader.getExtensionLoader(JsonOperator.class).getExtension(jsonType);
		}catch(Exception e){
			logger.error(LogConstant.JSON + " init error:", e);
		}
	}

	/**
	 * 将JSON字符串转化为Java对象
	 * @param jsonStr
	 * @param valueType
	 * @return Object，发生异常返回null
	 */
	public static <T> T jsonToObject(String jsonStr, Class<T> valueType) throws JsonDeserializationException {
		if(logger.isDebugEnabled()) {
			logger.debug(LogConstant.JSON + " jsonToObject str: {}", jsonStr);
		}
		return jsonOperator.jsonToObject(jsonStr, valueType);
	}

	/**将JSON字符串转化为Java对象(支持普通类和容器类)
	 * @param jsonStr
	 * @param entityClass
	 * @return
	 */
	public static <T> T jsonToObject(String jsonStr, JsonContainerClass<T> entityClass) throws JsonDeserializationException {
		if(logger.isDebugEnabled()) {
			logger.debug(LogConstant.JSON + " jsonToObject str: {}", jsonStr);
		}
		return jsonOperator.jsonToObject(jsonStr, entityClass);
	}

	/**
	 * 将json字符串转化为泛型容器，如map
	 * @author sangshan
	 * @param jsonStr 待转化json字符串
	 * @param containerClass 容器Class类
	 * @param genericsClasses 可变参数列表，表示容器泛型Class类
	 * @return 转化后的泛型容器
	 * *******************
	 * 例
	 * class User{}//用户数据，略
	 * String str = "{\"wjq\":{...},\"zsl\":{...}}";
	 * JacksonUtil.jsonToGenericContainer(str,Map.class,String.class,User.class);
	 */
	public static <T> T jsonToGenericContainer(String jsonStr, Class<?> containerClass, Class<?>... genericsClasses) throws JsonDeserializationException {
		if(logger.isDebugEnabled()) {
			logger.debug(LogConstant.JSON + " jsonToObject str: {}", jsonStr);
		}
		return jsonOperator.jsonToGenericContainer(jsonStr, containerClass, genericsClasses);
	}

	/**
	 * 将java对象转化为JSON
	 * @param object
	 * @return jsonStr，如果序列化失败返回null
	 */
	public static String objecttoJSon(Object object) {
		return jsonOperator.objecttoJSon(object);
	}

	/**
	 * 将java对象转化为JSON，java对象必须实现序列化接口
	 * @param object
	 * @return jsonStr，如果序列化失败返回指定字符串
	 */
	public static String serializableObjecttoJSon(Object object, String defaultString) {
		return jsonOperator.serializableObjecttoJSon(object, defaultString);
	}
	
	/**往json串的currentNodeName节点下写入新值
	 * @param jsonStr
	 * @param currentNodeName 
	 * @param values 
	 * @return 新的json字符串
	 */
	public static String putValue(String jsonStr, String currentNodeName, List<TwoTuple<String, Object>> values) {
		return jsonOperator.putValue(jsonStr, currentNodeName, values);
	}
	
	/**删除paths路径下的指定节点
	 * @param jsonStr
	 * @param deleteNodeName
	 * @param paths
	 * @return
	 */
	public static String deleteValue(String jsonStr, String deleteNodeName, String... paths) {
		return jsonOperator.deleteValue(jsonStr, deleteNodeName, paths);
	}
	
	public static JsonNode getJsonNode(String result) {
		Objects.requireNonNull(result, "result json must not null");
		return parseJsonNode(result, (String[])null);
	}
	
	private static JsonNode parseJsonNode(String json, String... paths) {
		return jsonOperator.parseJsonNode(json, paths);
	}
	
	public static String getString(String json, String... paths) {
		return jsonOperator.getString(json, paths);
	}

	public static <T> T getPathObject(String json, Class<T> clazz, String... paths) {
		return jsonOperator.getPathObject(json, clazz, paths);
	}

	public static <T> List<T> getPathArray(String json, Class<T> clazz, String... paths){
		return jsonOperator.getPathArray(json, clazz, paths);
	}
	
	public static <T, U> Map<T, U> getPathMap(String json, Class<T> keyClazz, Class<U> valueClazz, String... paths){
		return jsonOperator.getPathMap(json, keyClazz, valueClazz, paths);
	}
	
}